package ngat.oss;

import ngat.message.OSS.*;
import ngat.util.logging.*;

import java.text.*;
import java.util.*;

/**
 * The superclass of all Client requests for access to the Phase II database.
 * Clients include: {RCS, Users, Dprt, and Admin}. 
 */
public abstract class TransactionImpl {
    
    /** Generic ISO8601 Date format.*/
    public static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd 'T' HH:mm:ss z");

    /** The TRANSACTION with which this instance of TransactionImpl
     * is associated - i.e. the TRANSACTION it will implement.*/
    TRANSACTION request;

    /** A (unique?) id for this TransactionImpl.*/
    protected String id;

    /** The class name of the Transaction being implemented.*/
    protected String CLASS;
    
    /** A general Logger for use by individual TransactionImpls. 
     * The Logger defaults to "OSS" but can be replaced using
     * the setLogger(String) method. Do this early on before
     * any TRANSACTIONS are implemented.*/
    protected static Logger logger;

    /** A special Logger for any subclass  of TransactionImpl
     * to set and make use of as required. These will need to have
     * been setup in advance and must be selected on entry to the Impl's
     * overridden exec() method.
     */
    protected Logger myLog;

    /** A Buffer to hold logging information during implementation of the transaction.
     * This is re-initialized whenever a TransactionImpl is created.
     */
    protected StringBuffer logBuffer;

    /** Create a TransactionImpl with the id 'untitled'.*/
    public TransactionImpl() {
	this("untitled");
    } 
    
    /** Create a TransactionImpl with the specified id.
     * @Param id The name/id of this instance.*/
    public TransactionImpl(String id) {
	this.id = id;
	if (logger == null)
	    logger = LogManager.getLogger("OSS");
	CLASS = "";
    }
    
    /** Create a TransactionImpl with id made up from the TRANSACTION
     * which it is implementing. Subclasses should override to carry out
     * the transfer of any internal data required for implementation.
     * @param request The TRANSACTION to be implemented.*/
    public TransactionImpl(TRANSACTION request){
	this(request.getId());
	this.request = request;
	CLASS = request.getTransIdent();
	logBuffer = new StringBuffer(request.getTransIdent());
    }
    
    /** Method to carry out the TRANSACTION operation.
     * This method <b>must</b> be overridden by subclasses.
     * @return A TRANSACTION_DONE carrying any data to return to the client.
     */
    public abstract TRANSACTION_DONE exec();
    
    /** Generates a basic TRANSACTION_DONE with error information setup.
     * Use this for generic error replies. May need specific DONE
     * subclasses if specialist information must be returned.
     * @param id          The ID for this message (usually created from the requested TRANSACTION.
     * @param errorNum    The event-specific error-code.
     * @param errorString A message for the client.  
     * @param exception   An optional Exception which caused the failure.
     */
    public TRANSACTION_DONE error(String id, int errorNum, String errorString, Exception exception) {
	TRANSACTION_DONE done = new TRANSACTION_DONE(id);
	done.setSuccessful(false);
	done.setErrorNum(errorNum);
	done.setErrorString(errorString);
	done.setException(exception);
	return done;
    }

    /** Generates a basic TRANSACTION_DONE with error information setup.
     * Use this for generic error replies. May need specific DONE
     * subclasses if specialist information must be returned.
     * @param id          The ID for this message (usually created from the requested TRANSACTION.
     * @param errorNum    The event-specific error-code.
     * @param errorString A message for the client.  
     */
    public TRANSACTION_DONE error(String id, int errorNum, String errorString) {
	TRANSACTION_DONE done = new TRANSACTION_DONE(id);
	done.setSuccessful(false);
	done.setErrorNum(errorNum);
	done.setErrorString(errorString);
	return done;
    }

    /** Generates a basic TRANSACTION_DONE with error information setup.
     * Use this for generic error replies. May need specific DONE
     * subclasses if specialist information must be returned. This
     * constructor uses the id already received from the request. 
     * @param errorNum    The event-specific error-code.
     * @param errorString A message for the client.
     * @param exception   An optional Exception which caused the failure.  
     */
    public TRANSACTION_DONE error(int errorNum, String errorString, Exception exception) {
	return error(id, errorNum, errorString);
    }
    
    /** Generates a basic TRANSACTION_DONE with error information setup.
     * Use this for generic error replies. May need specific DONE
     * subclasses if specialist information must be returned. This
     * constructor uses the id already received from the request. 
     * @param errorNum    The event-specific error-code.
     * @param errorString A message for the client.     
     */
    public TRANSACTION_DONE error(int errorNum, String errorString) {
	return error("", errorNum, errorString);
    }

    /** Returns the TRANSACTION being implemented or null if no
     * specific request is currently associated with this TransactionImpl.
     */
    public TRANSACTION getRequest() { return request; }
    
    /** Sets the TRANSACTION to be implemented - this can save on
     * construction costs by keeping an Impl around to service a series of
     * requests - care should be taken to null the request when exec() returns
     * as otherwise the value returned by getRequest() will be out of date. It 
     * is also important to ensure any subclass specific internal state variables
     * are also cleared out between requests as otherwise their accessors may 
     * return incorrect values.*/
    public void setRequest(TRANSACTION request) { this.request = request; }

    /** Sets the generic Logger for TransactionImplementors.
     * @param logger The name of the generic logger.
     */
    public void setLogger(String name) {
	logger = LogManager.getLogger(name);
    }

}
